import * as THREE from "three";
import { ThreeHelper } from "@/ThreeHelper";
import { MethodBaseSceneSet, LoadGLTF } from "@/ThreeHelper/decorators";
import { MainScreen } from "./Canvas";
import type { GLTF } from "three/examples/jsm/loaders/GLTFLoader.js";
import { Injectable } from "@/ThreeHelper/decorators/DI";
import type { GUI } from "dat.gui";
import gsap from "gsap";

import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js";
import { OutputPass } from "three/examples/jsm/postprocessing/OutputPass.js";
import { FXAAShader } from "three/examples/jsm/shaders/FXAAShader.js";
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js";
import EventMesh, { type BackIntersection } from "@/ThreeHelper/decorators/EventMesh";
import { FresnelMaterial } from "@/ThreeHelper/shader/material/FresnelMaterial";
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass.js";
import { UserEffectComposer } from "@/ThreeHelper/utils/useEffectComposer";

const BLOOM_SCENE = 1;

const bloomLayer = new THREE.Layers();
bloomLayer.set(BLOOM_SCENE);

@Injectable
// @ThreeHelper.useWebGPU
export class Main extends MainScreen {
    static instance: Main;
    selectedObjects: Object3D[] = [];
    darkMaterial = new THREE.MeshBasicMaterial({ color: "black" });
    materials: Record<string, THREE.Material> = {};
    composer: UserEffectComposer;

    constructor(private helper: ThreeHelper) {
        // private composer: UserEffectComposer
        super(helper);
        helper.main = this;

        this.composer = new UserEffectComposer();

        this.init();
        Main.instance = this;
    }

    @MethodBaseSceneSet({
        addAxis: 0,
        cameraPosition: new THREE.Vector3(0, 9, 25),
        cameraTarget: new THREE.Vector3(0, 9, 0),
        useRoomLight: true,
        near: 0.1,
        far: 800,
    })
    init() {
        // this.helper.renderer.setPixelRatio(window.devicePixelRatio);
        this.helper.renderer.setPixelRatio(1);

        // this.composer = new UserEffectComposer();

        console.log("this.composer:", this.composer);

        this.addLight();

        this.loadModel();

        this.handleScene();
    }

    handleScene() {
        const floor = this.helper.create.plane(10, 10);

        floor.material(
            new THREE.MeshStandardMaterial({
                color: new THREE.Color("#ffffff"),
                roughness: 0,
                metalness: 0,
            })
        );

        floor.mesh.rotateX(Math.PI / -2);

        floor.add();

        // EventMesh.appendIntersectObjects([floor.mesh]);
    }

    @EventMesh.OnMouseDown(Main)
    onMouseDown(RayInfo: BackIntersection, _: undefined, event: MouseEvent) {
        if (RayInfo.object) {
            console.log("down", RayInfo);
            EventMesh.enabledMouseMove = true;

            if (RayInfo.intersects.length > 1) {
                this.composer.toggleBloom(RayInfo.intersects[1].object);
            } else {
                this.composer.toggleBloom(RayInfo.object);
            }
            // this.composer.setBloom(...RayInfo.intersects.map(i => i.object));
        }
    }

    @EventMesh.OnMouseMove(Main, true)
    onMouseMove(event: MouseEvent, RayInfo: BackIntersection) {
        const target = event.target as HTMLElement;

        if (target.nodeName !== "CANVAS" || !target.getAttribute("data-engine")) {
            return;
        }

        if (RayInfo.object) {
            // console.log("move", RayInfo.distance);
            if (RayInfo.intersects.length > 1) {
                return this.composer.setSelectedObjects(RayInfo.intersects[1].object);
            } else {
                return this.composer.setSelectedObjects(RayInfo.object);
            }
        } else {
            this.composer.setSelectedObjects();
        }
    }

    @EventMesh.OnMouseUp(Main)
    onMouseUp(event: MouseEvent) {
        const target = event.target as HTMLElement;

        // if (!target || target.nodeName != "CANVAS") return;

        // EventMesh.enabledMouseMove = false;
        // this.helper.controls.enabled = true;
    }

    @LoadGLTF("/public/models/人体.glb")
    loadModel(gltf?: GLTF) {
        if (gltf) {
            this.helper.add(gltf.scene);
            console.log(gltf.scene);

            const human = gltf.scene.getObjectByName("human") as THREE.Mesh;

            if (human && human.isMesh) {
                human.material = new FresnelMaterial();
                human.userData.darkMaterial = new FresnelMaterial({
                    solidColor: new THREE.Vector4(...new THREE.Color(0, 0, 0), 1),
                });
            }

            const hart = gltf.scene.getObjectByName("hart") as Mesh;

            if (hart && hart.isMesh) {
                hart.material = new FresnelMaterial({
                    threshold: 0.75,
                    discard: false,
                    voidColor: new THREE.Vector4(...new THREE.Color(1, 0, 0), 0.2),
                });
            }
        }
    }

    @ThreeHelper.InjectAnimation(Main)
    animation() {}

    @ThreeHelper.AddGUI(Main)
    createEnvTexture(gui: GUI) {
        // gui.addFunction(async () => {}, "1");
    }

    addLight() {
        const light = new THREE.PointLight(0xffffff, 10, 20, 2);
        light.position.set(0, 2, 0);

        this.helper.scene.add(light);

        light.castShadow = true;
        light.shadow.mapSize.width = 1024 * 2;
        light.shadow.mapSize.height = 1024 * 2;
        light.shadow.camera.near = 0.3;
        light.shadow.camera.far = 200;
        light.shadow.bias = -0.0012;
        light.shadow.intensity = 1000;

        const shadowFolder = this.helper.gui?.addFolder("shadow");
        shadowFolder?.add(light.shadow, "intensity", 0, 100).name("强度💪");
        shadowFolder?.add(light.shadow, "bias").name("偏移量");
        shadowFolder?.add(light, "intensity", 0, 1000).name("点光源强度");

        this.helper.renderer.shadowMap.enabled = true;
        // this.helper.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        this.helper.renderer.shadowMap.type = THREE.BasicShadowMap;

        const skyColor = 0xffffff; // light blue
        const groundColor = 0x000000; // brownish orange
        const intensity = 2;
        const hemisphereLight = new THREE.HemisphereLight(skyColor, groundColor, intensity);
        // this.helper.scene.add(hemisphereLight);
    }
}
